home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
dev
/
devSCSIRobot.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
19KB
|
741 lines
/*
* devSCSIRobot.c --
*
* The standard Open, IOControl, and Close operations
* are defined here for a SCSI Tape Robot.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
* Copyright 1992 Regents of the University of California
* All rights reserved.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/devSCSIRobot.c,v 9.4 92/05/13 13:23:53 mottsmth Exp $ SPRITE (Berkeley)";
#endif not lint
#include <sprite.h>
#include <stdio.h>
#include <bstring.h>
#include <string.h>
#include <fs.h>
#include <dev.h>
#include <devInt.h>
#include <sys/scsi.h>
#include <scsiDevice.h>
#include <devSCSIRobot.h>
#include <dev/scsi.h>
#include <stdlib.h>
#include <dbg.h>
#include <mach.h>
static ReturnStatus InitExbRobot _ARGS_((Fs_Device *devicePtr,
ScsiDevice *devPtr));
static ReturnStatus InitError _ARGS_((ScsiDevice *devPtr,
ScsiCmd *scsiCmdPtr));
/*
*----------------------------------------------------------------------
*
* InitError --
*
* Initial error proc used by InitExbRobot when it is initializing
* things for the real error handlers.
*
* Results:
* DEV_OFFLINE if the device is offline, SUCCESS otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static ReturnStatus
InitError(devPtr, scsiCmdPtr)
ScsiDevice *devPtr; /* SCSI device that's complaining. */
ScsiCmd *scsiCmdPtr; /* SCSI command that had the problem. */
{
ScsiStatus *scsiStatusPtr;
unsigned char statusByte;
ScsiClass7Sense *sensePtr;
statusByte = (unsigned char) scsiCmdPtr->statusByte;
scsiStatusPtr = (ScsiStatus *) &statusByte;
if (!scsiStatusPtr->check) {
if (scsiStatusPtr->busy) {
return DEV_OFFLINE;
}
return SUCCESS;
}
sensePtr = (ScsiClass7Sense *) scsiCmdPtr->senseBuffer;
if (sensePtr->key == SCSI_CLASS7_NOT_READY) {
return DEV_OFFLINE;
}
if (sensePtr->key == SCSI_CLASS7_NO_SENSE) {
return SUCCESS;
}
return FAILURE;
}
/*
*----------------------------------------------------------------------
*
* InitExbRobot --
*
* Initialize the device driver state for a EXB-120 tape robot.
*
* Results:
* SUCCESS, if the robot driver is successfully initialized. A
* Sprite error code otherwise.
*
* Side effects:
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static ReturnStatus
InitExbRobot(devicePtr, devPtr)
Fs_Device *devicePtr; /* Device info, unit number, etc. */
ScsiDevice *devPtr; /* Attached EXB-120. */
{
ScsiExbRobot robotData;
ScsiExbRobot *robotPtr;
ReturnStatus status;
ExbRobotInquiryData *inquiryDataPtr;
/*
* Determine the type of device from the inquiry return
* by the attach. Reject device if not a jukebox.
*/
inquiryDataPtr = (ExbRobotInquiryData *) (devPtr->inquiryDataPtr);
if (devPtr->inquiryLength > 0) {
if (inquiryDataPtr->type != SCSI_MEDIUM_CHANGER_TYPE ||
devPtr->inquiryLength != sizeof(ExbRobotInquiryData)) {
return DEV_NO_DEVICE;
}
}
devPtr->errorProc = InitError;
/*
* Do a quick test to see if the device is ready.
*/
status = DevScsiTestReady(devPtr);
if (status != SUCCESS) {
/*
* Give up if it still isn't ready.
*/
status = DevScsiTestReady(devPtr);
if (status != SUCCESS) {
return status;
}
}
if (devicePtr->data == (ClientData) NIL) {
robotPtr = &robotData;
bzero((char *) robotPtr, sizeof(ScsiExbRobot));
robotPtr->devPtr = devPtr;
robotPtr->state = SCSI_ROBOT_CLOSED;
robotPtr->name = "SCSI Robot";
robotPtr->chmAddr = (unsigned) 0x79; /* Default. */
}
else {
robotPtr = (ScsiExbRobot *) (devicePtr->data);
}
/*
* Allocate and return the ScsiExbRobot structure in the data field
* of the Fs_Device.
*/
if (status == SUCCESS && devicePtr->data == (ClientData) NIL) {
robotPtr = (ScsiExbRobot *) malloc(sizeof(ScsiExbRobot));
*robotPtr = robotData;
devicePtr->data = (ClientData) robotPtr;
devPtr->clientData = (ClientData) robotPtr;
if (devPtr->errorProc == InitError) {
devPtr->errorProc = DevSCSIExbRobotError;
}
}
return status;
}
/*
*----------------------------------------------------------------------
*
* DevSCSIExbRobotError --
*
* Map SCSI errors indicated by the sense data into Sprite ReturnStatus
* and error message. This proceedure handles two types of
* sense data Class 0 and class 7.
*
* Results:
* A sprite error code.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
ReturnStatus
DevSCSIExbRobotError(devPtr, scsiCmdPtr)
ScsiDevice *devPtr; /* SCSI Device that's complaining. */
ScsiCmd *scsiCmdPtr; /* SCSI command that had the problem. */
{
char errorString[MAX_SCSI_ERROR_STRING];
char *name;
ScsiExbRobot *robotPtr;
int senseLength;
ScsiClass0Sense *sensePtr;
unsigned char statusByte;
ScsiStatus *statusPtr;
ReturnStatus status;
statusByte = scsiCmdPtr->statusByte;
statusPtr = (ScsiStatus *) &statusByte;
sensePtr = (ScsiClass0Sense *) scsiCmdPtr->senseBuffer;
senseLength = scsiCmdPtr->senseLen;
robotPtr = (ScsiExbRobot *) devPtr->clientData;
name = devPtr->locationName;
if (!statusPtr->check) {
if (SCSI_RESERVED_STATUS(statusByte) || statusPtr->intStatus) {
printf("Warning: %s at %s unknown status byte 0x%x\n",
robotPtr->name, name, statusByte);
return SUCCESS;
}
if (statusPtr->busy) {
return DEV_OFFLINE;
}
return SUCCESS;
}
if (senseLength == 0) {
printf("Warning: %s at %s error: no sense data\n", robotPtr->name, name);
return DEV_NO_SENSE;
}
/*
* The EXB-120 only returns class 7 (extended sense) data.
*/
DevScsiMapClass7Sense(senseLength, (char *)sensePtr,
&status, errorString);
if (errorString[0]) {
printf("Warning: %s at %s error: %s\n", robotPtr->name, name,
errorString);
}
return status;
}
/*
*---------------------------------------------------------------------
*
* DevSCSIExbRobotOpen --
*
* Open an EXB-120 jukebox robot as a file. This routine verifies
* the device's existence and sets any special mode flags.
*
* Results:
* SUCCESS if the device is online.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------
*/
/* ARGSUSED */
ReturnStatus
DevSCSIExbRobotOpen(devicePtr, useFlags, token, flagsPtr)
Fs_Device *devicePtr; /* Device info, lun, etc. */
int useFlags; /* Flags from the stream being opened (unused) */
Fs_NotifyToken token; /* Call-back token for input (unused) */
int *flagsPtr; /* OUT: Device flags (unused) */
{
ReturnStatus status;
ScsiDevice *devPtr;
ScsiExbRobot *robotPtr;
robotPtr = (ScsiExbRobot *) (devicePtr->data);
if (robotPtr == (ScsiExbRobot *) NIL) {
/*
* Ask the HBA to set up the path to the device with FIFO ordering
* of requests.
*/
devPtr = DevScsiAttachDevice(devicePtr, DEV_QUEUE_FIFO_INSERT);
if (devPtr == (ScsiDevice *) NIL) {
return DEV_NO_DEVICE;
}
}
else {
/*
* If the robotPtr is already attached to the device, it must
* be busy.
*/
return FS_FILE_BUSY;
}
status = InitExbRobot(devicePtr, devPtr);
return status;
}
/*---------------------------------------------------------------------
*
* DevSCSIExbRobotClose --
*
* Close an EXB-120 jukebox. Free all data structures associated
* with the jukebox.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
ReturnStatus
DevSCSIExbRobotClose(devicePtr, useFlags, openCount, writerCount)
Fs_Device *devicePtr;
int useFlags;
int openCount;
int writerCount;
{
ScsiExbRobot *robotPtr;
ReturnStatus status;
status = SUCCESS; /* There's no way we can fail. */
robotPtr = (ScsiExbRobot *) (devicePtr->data);
if (openCount > 0) {
return status;
}
(void) DevScsiReleaseDevice(robotPtr->devPtr);
free((char *) robotPtr);
devicePtr->data = (ClientData) NIL;
return status;
}
/*
*------------------------------------------------------------------------
*
* DevSCSIExbRobotIOControl --
*
* Do operations on the Exabyte EXB-120 Robot.
*
* Results:
* The Sprite status.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
/*ARGSUSED*/
ReturnStatus
DevSCSIExbRobotIOControl(devicePtr, ioctlPtr, replyPtr)
Fs_Device *devicePtr;
Fs_IOCParam *ioctlPtr; /* Standard I/O Control parameter block */
Fs_IOReply *replyPtr; /* Size of outBuffer and returned signal */
{
ScsiExbRobot *robotPtr;
ScsiCmd scsiRobotCmd;
ReturnStatus status;
Dev_RobotCommand *cmdPtr;
int scsiCmd;
int amountTransferred;
ExbRobotModeSelectData modeSelData;
bzero((char *) &scsiRobotCmd, sizeof(ScsiCmd));
robotPtr = (ScsiExbRobot *) (devicePtr->data);
if ((ioctlPtr->command & ~0xffff) == IOC_SCSI) {
status = DevScsiIOControl(robotPtr->devPtr, ioctlPtr, replyPtr);
return status;
}
cmdPtr = (Dev_RobotCommand *) ioctlPtr->inBuffer;
amountTransferred = 0;
switch (ioctlPtr->command) {
case IOC_ROBOT_INIT_ELEM_STATUS:
scsiCmd = SCSI_INIT_ELEM_STATUS;
ExbRobotInitElemStatus(&scsiRobotCmd, cmdPtr);
break;
case IOC_ROBOT_INQUIRY:
scsiCmd = SCSI_INQUIRY;
if (ioctlPtr->outBuffer == NULL) {
return DEV_INVALID_ARG;
}
ExbRobotInquiry(&scsiRobotCmd,
(ExbRobotInquiryData *)ioctlPtr->outBuffer);
break;
case IOC_ROBOT_MODE_SEL:
scsiCmd = SCSI_MODE_SELECT;
ExbModeSelect(&scsiRobotCmd, cmdPtr, NULL, 0);
break;
case IOC_ROBOT_DISPLAY:
scsiCmd = SCSI_MODE_SELECT;
bzero((char *) &modeSelData, sizeof(ExbRobotModeSelectData));
ExbModeSelect(&scsiRobotCmd, cmdPtr,
(Address)&modeSelData, sizeof(modeSelData));
break;
case IOC_ROBOT_MOVE_MEDIUM:
scsiCmd = SCSI_MOVE_MEDIUM;
ExbMoveMedium(&scsiRobotCmd, robotPtr, cmdPtr);
break;
case IOC_ROBOT_POS_ELEM:
scsiCmd = SCSI_POSITION_ELEMENT;
ExbPosElem(&scsiRobotCmd, robotPtr, cmdPtr);
break;
case IOC_ROBOT_PREV_REMOVAL:
scsiCmd = SCSI_PREVENT_ALLOW;
ExbPrevRemoval(&scsiRobotCmd, cmdPtr);
break;
case IOC_ROBOT_NO_OP:
scsiCmd = SCSI_TEST_UNIT_READY;
scsiRobotCmd.commandBlockLen = 6;
break;
case IOC_ROBOT_REQ_SENSE:
scsiCmd = SCSI_REQUEST_SENSE;
if (ioctlPtr->outBuffer == NULL) {
return DEV_INVALID_ARG;
}
ExbReqSense(&scsiRobotCmd,
(ExbRobotSenseData *)ioctlPtr->outBuffer);
break;
default:
/* Invalid or Command not supported. */
scsiCmd = 0;
panic("Fs_IOControl -- Tape Robot: Unknown command %d\n",
ioctlPtr->command);
}
/* Since we've set up the SCSI CDB, send the block out. */
status = DevScsiSendCmdSync(robotPtr->devPtr, &scsiRobotCmd,
&amountTransferred);
return status;
}
/*
*---------------------------------------------------------------------
*
* ExbRobotInitElemStatus --
*
* Fill in the SCSI CDB for an InitElemStatus command to an Exabyte
* EXB-120 robot.
*
* Results:
* None.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------
*/
void
ExbRobotInitElemStatus(scsiRobotCmdPtr, cmdPtr)
ScsiCmd *scsiRobotCmdPtr;
Dev_RobotCommand *cmdPtr;
{
InitElemStatCommand *cdbPtr;
cdbPtr = (InitElemStatCommand *) scsiRobotCmdPtr->commandBlock;
bzero((char *) cdbPtr, sizeof(InitElemStatCommand));
scsiRobotCmdPtr->dataToDevice = FALSE;
scsiRobotCmdPtr->commandBlockLen = sizeof(InitElemStatCommand);
/*
* Fill in Command Descriptor Block. All fields are initially assumed
* to contain 0.
*/
cdbPtr->command = SCSI_INIT_ELEM_STATUS;
cdbPtr->unitNumber = 0;
cdbPtr->range = cmdPtr->range;
cdbPtr->elemAddr[0] = (cmdPtr->elemAddr) >> 8;
cdbPtr->elemAddr[1] = ((cmdPtr->elemAddr) << 24) >> 24;
cdbPtr->numElements[0] = (cmdPtr->numElements) >> 8;
cdbPtr->numElements[1] = ((cmdPtr->numElements) << 24) >> 24;
}
/*
*---------------------------------------------------------------------
*
* ExbRobotInquiry --
*
* Fill in the SCSI CDB for an Inquiry command to an Exabyte
* EXB-120 robot.
*
* Results:
* None.
*
* Side effects:
*
*
*---------------------------------------------------------------------
*/
void
ExbRobotInquiry(scsiRobotCmdPtr, inquiryDataPtr)
ScsiCmd *scsiRobotCmdPtr;
ExbRobotInquiryData *inquiryDataPtr;
{
ScsiInquiryCommand *cdbPtr;
cdbPtr = (ScsiInquiryCommand *) scsiRobotCmdPtr->commandBlock;
bzero((char *) cdbPtr, sizeof(ScsiInquiryCommand));
scsiRobotCmdPtr->dataToDevice = FALSE;
scsiRobotCmdPtr->bufferLen = sizeof(ExbRobotInquiryData);
scsiRobotCmdPtr->buffer = (Address) inquiryDataPtr;
scsiRobotCmdPtr->commandBlockLen = sizeof(ScsiInquiryCommand);
/*
* Fill in Command Descriptor Block. All fields are initially assumed
* to contain 0.
*/
cdbPtr->command = SCSI_INQUIRY;
cdbPtr->unitNumber = 0;
cdbPtr->allocLength = sizeof(ExbRobotInquiryData);
}
/*----------------------------------------------------------------
*
* ExbModeSelect --
*
* Fill in the SCSI CDB for a Mode Select Command to an
* Exabyte EXB-120 robot.
*
* Results:
* None.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------
*/
void
ExbModeSelect(scsiRobotCmdPtr, cmdPtr, dataPtr, dataLength)
ScsiCmd *scsiRobotCmdPtr;
Dev_RobotCommand *cmdPtr;
Address dataPtr;
unsigned int dataLength;
{
ScsiModeSelectCommand *cdbPtr;
cdbPtr = (ScsiModeSelectCommand *) scsiRobotCmdPtr->commandBlock;
if (dataPtr != NULL) {
scsiRobotCmdPtr->dataToDevice = TRUE;
((ExbRobotModeSelectData *) dataPtr)->vendorUnique.mesgDispCntrl =
cmdPtr->mesgDisplay;
strncpy(((ExbRobotModeSelectData *) dataPtr)->vendorUnique.displayMessage,
cmdPtr->mesgString, 60);
((ExbRobotModeSelectData *) dataPtr)->vendorUnique.paramListLength = 62;
}
else {
scsiRobotCmdPtr->dataToDevice = FALSE;
}
scsiRobotCmdPtr->commandBlockLen = sizeof(ScsiModeSelectCommand);
scsiRobotCmdPtr->buffer = dataPtr;
scsiRobotCmdPtr->bufferLen = 68;
/* Fill in Command Descriptor Block. */
cdbPtr->command = SCSI_MODE_SELECT;
cdbPtr->unitNumber = 0;
cdbPtr->pageFormat = 1;
cdbPtr->savedPage = cmdPtr->savedPage;
cdbPtr->paramListLength = dataLength;
}
/*
*---------------------------------------------------------------------
*
* ExbMoveMedium --
*
* Fill in the SCSI CDB for a MoveMedium command to an Exabyte
* EXB-120 robot.
*
* Results:
* None.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------
*/
void
ExbMoveMedium(scsiRobotCmdPtr, robotPtr, cmdPtr)
ScsiCmd *scsiRobotCmdPtr;
ScsiExbRobot *robotPtr;
Dev_RobotCommand *cmdPtr;
{
MoveMediumCommand *cdbPtr;
cdbPtr = (MoveMediumCommand *) scsiRobotCmdPtr->commandBlock;
bzero((char *) cdbPtr, sizeof(MoveMediumCommand));
scsiRobotCmdPtr->dataToDevice = FALSE;
scsiRobotCmdPtr->bufferLen = 0;
scsiRobotCmdPtr->commandBlockLen = sizeof(MoveMediumCommand);
/* Fill in CDB. */
cdbPtr->command = SCSI_MOVE_MEDIUM;
cdbPtr->unitNumber = 0;
cdbPtr->transpElemAddr[1] = (robotPtr->chmAddr << 24) >> 24;
cdbPtr->transpElemAddr[0] = robotPtr->chmAddr >> 8;
cdbPtr->sourceAddr[1] = ((cmdPtr->sourceAddr) << 24) >> 24;
cdbPtr->sourceAddr[0] = (cmdPtr->sourceAddr) >> 8;
cdbPtr->destAddr[1] = ((cmdPtr->destAddr) << 24) >> 24;
cdbPtr->destAddr[0] = (cmdPtr->destAddr) >> 8;
cdbPtr->eePos = cmdPtr->eePos;
}
/*--------------------------------------------------------------------
*
* ExbPosElem --
*
* Fill in the SCSI CDB for a PositionToElement command to an
* Exabyte EXB-120 robot.
*
* Results:
* None.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------
*/
void
ExbPosElem(scsiRobotCmdPtr, robotPtr, cmdPtr)
ScsiCmd *scsiRobotCmdPtr;
ScsiExbRobot *robotPtr;
Dev_RobotCommand *cmdPtr;
{
PositionRobotCommand *cdbPtr;
cdbPtr = (PositionRobotCommand *) scsiRobotCmdPtr->commandBlock;
bzero((char *) cdbPtr, sizeof(PositionRobotCommand));
scsiRobotCmdPtr->commandBlockLen = sizeof(PositionRobotCommand);
scsiRobotCmdPtr->bufferLen = 0;
/* Fill in CDB. */
cdbPtr->command = SCSI_POSITION_ELEMENT; /* Position to Element Command. */
cdbPtr->unitNumber = 0;
cdbPtr->transpElemAddr[1] = (robotPtr->chmAddr << 24) >> 24;
cdbPtr->transpElemAddr[0] = robotPtr->chmAddr >> 8;
cdbPtr->destAddr[1] = ((cmdPtr->destAddr) << 24) >> 24;
cdbPtr->destAddr[0] = (cmdPtr->destAddr) >> 8;
}
/*--------------------------------------------------------------------
*
* ExbPrevRemoval --
*
* Fill in the SCSI CDB for a Prevent/Allow Medium Removal
* command to an Exabyte EXB-120 robot.
*
* Results:
* None.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------
*/
void
ExbPrevRemoval(scsiRobotCmdPtr, cmdPtr)
ScsiCmd *scsiRobotCmdPtr;
Dev_RobotCommand *cmdPtr;
{
ScsiPreventAllowCmd *cdbPtr;
cdbPtr = (ScsiPreventAllowCmd *) scsiRobotCmdPtr->commandBlock;
scsiRobotCmdPtr->commandBlockLen = sizeof(ScsiPreventAllowCmd);
scsiRobotCmdPtr->bufferLen = 0;
/* Fill in CDB. */
cdbPtr->command = SCSI_PREVENT_ALLOW; /* 0x1e */
cdbPtr->unitNumber = 0;
cdbPtr->prevent = cmdPtr->prevAllow;
}
/*--------------------------------------------------------------------
*
* ExbReqSense --
*
* Fill in the SCSI CDB for a RequestSense command
* to be sent to an Exabyte EXB-120 robot.
*
* Results:
* None.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------
*/
void
ExbReqSense(scsiRobotCmdPtr, senseDataPtr)
ScsiCmd *scsiRobotCmdPtr;
ExbRobotSenseData *senseDataPtr;
{
ScsiRequestSenseCmd *cdbPtr;
cdbPtr = (ScsiRequestSenseCmd *) scsiRobotCmdPtr->commandBlock;
bzero((char *) cdbPtr, sizeof(ScsiRequestSenseCmd));
scsiRobotCmdPtr->dataToDevice = FALSE;
scsiRobotCmdPtr->commandBlockLen = sizeof(ScsiRequestSenseCmd);
scsiRobotCmdPtr->bufferLen = sizeof(ExbRobotSenseData);
scsiRobotCmdPtr->buffer = (Address) senseDataPtr;
/* Fill in CDB. */
cdbPtr->command = SCSI_REQUEST_SENSE; /* 0x3 */
cdbPtr->unitNumber = 0;
cdbPtr->allocLen = SCSI_EXB_ROBOT_SENSE_LEN;
}